<?php
/**
* View feeds in a variety of different formats.
*       Note that this file uses rewritten urls set in .htaccess
* Both types & tags use a pattern to break apart argument into an array.
* Delimited on + & -, treats all as a special case.  
*       EG: for all but files, pattern would be all-files.  
*       EG: for blog, folio, files, blog+folio+file.  
*       EG: for all tags except personal and education, all-personal-education
*
* @package folio
* @param string $user The user/community we're viewing. Can also include an optional pwd hash for external 
*       authentication that doesn't depend upon being logged in.
* @param string $mode What we're trying to view, all = everything, fac=friends & community, 
*       inbox = my activity, user= stuff user has done
* @param string $format The way that we're looking at the data, aka RSS / HTML / ...
* @param string $types The types of things we're looking at (see pattern) 
* @param string $tags The types of things we're looking at (see pattern)   NOTE: NOT YET IMPLEMENTED
* @param int $page The page of results we're looking at
*/
    define("context", "feeds");
    $itemsperpage = 10;


    // Used to keep an array of valid options
    $options = array( 
        'mode' => array(
            'var' => 'mode',
            'caption' => 'People', 
            'displaymode' => 'single', 
            'validate' => true, 
            'wildcard' => false, 
            'values' => array(
                'all' => array('name' => 'all', 'caption' => 'Everyone', 'showfor' => 'all'), 
                'fac' => array('name' => 'fac', 'caption' => 'Friends &amp; Community', 'showfor' => 'person'), 
                'inbox' => array('name' => 'inbox', 'caption' => 'Inbox', 'showfor' => 'all'), 
                'user' => array('name' => 'user', 'caption' => 'Just Me', 'showfor' => 'all'))),
        'format' => array( 
            'var' => 'format', 
            'validate' => false, 
            'displaymode' => 'single', 
            'caption' => 'Display', 
            'wildcard' => false, 
            'values' => array(
                'html' => array('name' => 'html', 'caption' => 'Full-text', 'showfor' => 'all'), 
                'summary' => array('name' => 'summary', 'caption' => 'Summary', 'showfor' => 'all'))),
        'types' => array(
            'var' => 'types',
            'validate' => true, 
            'caption' => 'Include', 
            'displaymode' => 'multiple', 
            'wildcard' => 'all', 
            'values' => array(
                'weblog' => array('name' => 'weblog', 'caption' => 'Blog Posts', 'showfor' => 'all'), 
                'weblog_comment' => array('name' => 'weblog_comment', 'caption' => 'Blog Comments', 'showfor' => 'all'),
                'file' => array('name' => 'file', 'caption' => 'Files', 'showfor' => 'all'),
                'page' => array('name' => 'page', 'caption' => 'Wiki Page', 'showfor' => 'all'),
                'page_comment' => array('name' => 'page_comment', 'caption' => 'Wiki Comments', 'showfor' => 'all'))),
        'username' => array(
            'var' => 'username',
            'caption' => 'User', 
            'validate' => false, 
            'displaymode' => false, 
            'wildcard' => 'all', 
            'values' => array() ), 
        'user_ident' => array(
            'var' => 'user_ident',
            'caption' => 'User Ident', 
            'displaymode' => false, 
            'validate' => false, 
            'wildcard' => 'all', 
            'values' => array() ),
        'tags' => array(
            'var' => 'tags',
            'caption' => 'Tags', 
            'displaymode' => false, 
            'validate' => false, 
            'wildcard' => 'all', 
            'values' => array() ) 
        );
    // Includes list of actual params
    $arguments = array();

    // Run includes
    require_once("../../../includes.php");
    require_once("../control/feeds.php");
    
    run("profile:init");
    run("friends:init");
    run("folio:init");
    global $metatags;

    // Create major variables.
    $reader_ident = -1; $readerhash=  '';

    // Create variables used to build html
    $from=0; $page=0; $results; $resultcount;
    
    // Load data from the GET variables & return.
    loadData( &$arguments, &$readerhash, &$page);

    // Run validation check.  if fail, -1 is returned.
    if ( $readerhash != '' ) {
        $reader_ident = folio_decodehash( $readerhash );
        if ( $reader_ident == -1 ) {
            error("Error, unable to validate your $readerhash username & hashed password value. Please log in and make sure you have the correct value.");
        }
    } elseif ( isloggedin() ) {
        // If we're looking at a RSS feed when logged in, show the public view if the pwd token
        //      hasn't been passed.  This is an obvious test case that people will use to see if
        //      Elgg is restricting access to the private/moderated/etc... content.
        if ( $arguments['format'][0] =='rss' ) {
            $reader_ident = -1;
        } else {
            $reader_ident = $_SESSION['userid'];
        }
    } else {
        $reader_ident = -1;
    }
    $page_owner = $arguments['user_ident'][0];

    // Build where clause for getting data
    $where = buildWhere( $reader_ident, $arguments );

    // Get Data
    getData( $where, $from, $page, &$results, &$resultcount);

    // Setup Metatags for RSS Discovery (with hashkey for loggedin users)
    if ( isloggedin() ) {
        $metatags .= "<link rel=\"alternate\" type=\"application/rss+xml\" title=\"RSS\" href=\"" . 
            folio_feeds_url( $arguments, 1, array( array('name'=>'format', 'value'=>'rss') ) ) . ':' . folio_createhash( $_SESSION['userid'] ) . "\"/>";
    } else {
        $metatags .= "<link rel=\"alternate\" type=\"application/rss+xml\" title=\"RSS\" href=\"" . 
            folio_feeds_url( $arguments, 1, array( array('name'=>'format','value'=>'rss') ) ) . '"/>';
    } 


    // Print results to the screen.
    echo returnHTML( $arguments, $results, $resultcount, $page ) ;

/**
* Same as folio_clean, except suitable for array_walk
**/
function folio_clean_array( &$result, $key ) {
    $result = folio_clean( $result);
}
    
/**
* Read in & validate information
**/
function loadData( &$arguments, &$readerhash, &$page) {
    // Retrieve passed variables 
    global $options;
    $avoid = array();

    $arguments['username'] = required_param('user');
    $arguments['format'] = required_param('format');
    $arguments['mode'] = required_param('mode');
    $arguments['types'] = str_replace( ' ', '+', required_param('types'));
    $arguments['tags'] = str_replace( ' ', '+', required_param('tags'));

    $page = intval( optional_param('page', 1, PARAM_INT) );
    $readerhash = optional_param('reader', '');

    //  Convert from a string with tag+tag-tag to an array.
    //     Don't use _avoid, unneeded with the new interface.
    foreach ( $arguments as $a_key => $a_valuearray ) {
        // Turn string into array
        folio_feed_parselist( $a_valuearray, &$a_valuearray, $avoid );
        array_walk(&$a_valuearray, 'folio_clean_array');

        // Validate all options
        foreach ( $a_valuearray as $a_value ) {
            // See if we should validate
            if  ( $options[$a_key]['validate'] ) {
                // Test against valid options & wildcard value.
                if  (   !array_key_exists( $a_value, $options[$a_key]['values'] ) 
                        AND $options[$a_key]['wildcard'] <> $a_value ) {
                    // Not found
                    trigger_error('Feeds.php Error :: Sorry, but the ' . $a_value . ' value passed for ' . 
                        $options[$a_key]['caption'] . ' is not valid.', E_USER_ERROR);
                }
            }
        }

        $arguments[$a_key] = $a_valuearray;
    }

    // Setup & Validate Owner
    if ( $arguments['username'][0] == 'all' AND $arguments['mode'][0] == 'all') {
        // Showing all activity
        $arguments['user_ident'] = array(-1);
    } else {
        // Showing activity for a specific user.
        $arguments['user_ident'] = array();

        foreach( $arguments['username'] as $name ) {

            if ( ! ( $arguments['user_ident'][] = run( 'users:name_to_id', $name ) ) ) {
                // Nothing returned by the run command, not a valid user.  
                trigger_error( 'Sorry, but "' . $name . '" is not a valid username in this system.', E_USER_ERROR);
            } 
        }
    }

    // SET CURRENT PAGE
    if ($page < 1) { $page = 1; }

}


/**
* Based off of the incoming parameters, build a SQL where condition
*   Integrates permissions via reader_ident.  That way, I can look at Bob's
*   list of events w/o seeing his private information.
**/
function buildWhere( $reader_ident, $arguments ) {
    global $CFG;

    // Build user filter
    if ( $arguments['mode'][0] == 'all') {
        // Find all activity system-wide.
        $where = ' true ';

    } elseif ( $arguments['mode'][0] == 'fac' ) {
        // FIND FRIENDS AND JOINED COMMUNITIES.
        $friendlist = recordset_to_array( /* Friends & joined communities */
                        get_recordset_sql( 
                        "SELECT DISTINCT friend as i, friend FROM " . $CFG->prefix . 
                        "friends where owner = " . implode( ',', $arguments['user_ident']) ));
        $f1 = recordset_to_array( /* owned communities */
                get_recordset_sql( 
                "SELECT DISTINCT ident as i, ident FROM " . $CFG->prefix . 
                "users where owner = " . implode( ',', $arguments['user_ident']) ));
        $friendlist = ( is_array($friendlist) ? $friendlist : array() );
        $f1 = ( is_array($f1) ? $f1: array() );
        $friendlist = array_merge( $friendlist, $f1 );
        $f1 = null;

        // Strip down to just the friend value.
        foreach( $friendlist as $f_key => $f_value ) {
            $friendlist[$f_key] = $f_value->i;
        }

        // Transform array into a where clause.
        if ( count( $friendlist ) > 0 ) {
            $where = ' owner_ident in (' . implode( ',', $friendlist) . ') and owner_ident <> ' .
                     implode( ',', $arguments['user_ident']) . ' and user_ident <> ' .
                     implode( ',', $arguments['user_ident']) . ' ';
        } else {
            // If a person has no friends or communities, then they have no activity.
            $where = " false ";
        }
    } elseif ( $arguments['mode'][0] == 'inbox' ) {
        // Show comments on blog posts that we're either interested in or authored.
        $prefix = $CFG->prefix;
        $where = " (
                (
                type_ident IN (
                    SELECT r.type_ident
                    FROM {$prefix}folio_rss r 
                    LEFT OUTER JOIN {$prefix}weblog_comments c
                    ON r.type_ident = c.ident AND r.type='weblog_comment'
                    LEFT OUTER JOIN {$prefix}weblog_posts p 
                    ON c.post_id = p.ident
                    WHERE p.owner IN ( " . implode( ',',$arguments['user_ident'] ) . " )
                    ) AND type IN ('weblog_comment', 'page_comment') 
                )
                OR (owner_ident IN ( " . implode( ',',$arguments['user_ident'] ) . ")
                    AND type IN ('weblog_comment', 'page_comment') ) 
                OR (type='weblog_comment' AND 
                    type_ident IN ( SELECT weblog_post FROM {$prefix}weblog_watchlist WHERE owner IN (
                        " . implode( ',',$arguments['user_ident'] ) . ") ) ) )";


    } elseif ( $arguments['mode'][0] == 'user' ) {
        // Subscribe to a person's feed.
        $where = " owner_ident IN (" . implode( ',', $arguments['user_ident']) . ') ';
    } else { trigger_error('unknown ' . $arguments['mode'][0] . ' purpose passed to feeds.php buildWhere', E_USER_ERROR); }

    // Add permissions
    $where .= ' AND access in ("' . implode( '","', rss_permissionlist( $reader_ident ) ) . '")';

    // Add type filter
    $where .= rss_buildwhere( 'type', $arguments['types'], array() );
//var_dump( $where );
    // Add tags filter
    // $where .= rss_buildwhere( 'type', $types, $types_avoid);

    return $where;
}


/**
* Get data using $where clause previously created.
**/
function getData( $where, $from, $page, &$results, &$resultcount) {
    global $itemsperpage;
    
    // Get count of results.
    $resultcount = rss_getcount( $where );
    
    // Build $from variable
    $from = ($page-1) * $itemsperpage;
    if ( $from > $resultcount ) { 
        trigger_error('Invalid page number ' . $page . ' passed to function folio_control_htmlfeed', E_USER_ERROR);
    }

    // Get individual results
    if ( $resultcount > 0 ) {
        $results = rss_getitems( $where, $from, $itemsperpage );
    } else {
        $results = false;
    }  
}

/**
* Build presentation data
**/    
    function returnHTML( $arguments, $results, $resultcount, $page ) {
        global $options;
        $url = url;
    
        $pagetitle = ' Activity :: ' . $options['mode']['values'][$arguments['mode'][0]]['caption'];

        if ( isloggedin() ) {
            $rsskey = ':' . folio_createhash( $_SESSION['userid'] . '/' );
        } else {
            $rsskey = '';
        }

        switch( $arguments['format'][0] ) {
            case 'html':

                $body = folio_feeds_controlbox( $arguments, $page ) . 
                        folio_control_htmlfeed( $results, $resultcount, $page, $arguments['username'], false ); 

                // Transfer into template & write.
                templates_page_setup();
                
                $users = array();
                foreach ( $arguments['username'] as $name ) {
                    $u = get_record_select('users',"username = '$name'");
                    $users[] = $u->name;
                }
                $body = templates_draw(array(
                        'context' => 'contentholder',
                        'title' => "<a href='" . folio_feeds_url ( $arguments, $page, 
                            array(  array( 'name'=>'format','value'=> 'rss'),
                                    array( 'name'=>'format','value'=> $arguments['format'][0])) ) . 
                        $rsskey . "'><img border=0 src='{$url}mod/folio/image/feed.png' /></a> " .
                        implode( ', ', $users ) . " :: $pagetitle ",
                        'body' => $body ));

                return templates_page_draw(array($pagetitle, $body));

                break;
            case 'summary':

                $body = folio_feeds_controlbox( $arguments, $page ) . 
                        folio_control_htmlfeed( $results, $resultcount, $page, 
                            implode( ', ', $arguments['username'] ), true ); 

                // Transfer into template & write.
                templates_page_setup();

                $users = array();
                foreach ( $arguments['username'] as $name ) {
                    $u = get_record_select('users',"username = '$name'");
                    $users[] = $u->name;
                }
                
                $body = templates_draw(array(
                        'context' => 'contentholder',
                        'title' => "<a href='" . folio_feeds_url ( $arguments, $page, 
                            array(  array( 'name'=>'format','value'=> 'rss'),
                                    array( 'name'=>'format','value'=> $arguments['format'][0])) ) . 
                        $rsskey . "'><img border=0 src='{$url}mod/folio/image/feed.png' /></a> " .
                        implode( ', ', $users ) . " :: $pagetitle ",
                        'body' => $body ));

                return templates_page_draw(array(
                        $pagetitle, $body
                    ));
                    
                break;

            case 'rss':
            
                $body = folio_control_rssfeed( $results, $resultcount, $arguments ); 
                
                header("Pragma: public");
                header("Cache-Control: public"); 
                header('Expires: ' . gmdate("D, d M Y H:i:s", (time()+3600)) . " GMT");
                
                $etag = md5($body);
                header('ETag: "' . $etag . '"');
                
                header("Content-Length: " . strlen($body));
                
                header("Content-type: text/xml; charset=utf-8");

                return $body;
                
                break;
            default:
                error('Invalid format passed to feeds.php');
                break;
        }
    }

/**
* Return the html control to allow the user a measure of control over selected what
*   to be in their feed or what not to be in their feed
* RETURNS html
**/
function folio_feeds_controlbox( $arguments, $page ) {
    global $options;
    
    // Get the user record, used later to only show appropriate options for communities.
    $rec = get_record('users','username',$arguments['username'][0]);
    
    // Start building HTML
    $html = '<table border=0 cellpadding=1 border-width=0 border-spacing=0>';

    // If we're looking at the wildcard type, then select all type options.
    if ( !(array_search( 'all', $arguments['types']) === false) ) {
        $arguments['types'] = array();
        foreach ( $options['types']['values'] as $v ) {
            $arguments['types'][] = $v['name'];
        }
    }

    // Create options, iterating thru array.
    foreach ( $options as $option ) {

        // Don't show displaymode == false options.
        if ( $option['displaymode'] == 'single' OR $option['displaymode'] == 'multiple') {

            $html .= "<tr><td><i>{$option['caption']}:</i></td><td>";

            // See if it's selected or not.
            foreach( $option['values'] as $option_value ) {
                // Show option value if it is enabled for the current user-type.
                if ( $option_value['showfor'] == 'all' OR 
                    $option_value['showfor'] == $rec->user_type ) {
                    // Look to see if the option is selected or not.
                    if ( in_array( $option_value['name'], $arguments[$option['var']]) ) {
                        // Selected
                        $html .= ($option['displaymode'] == 'multiple' ?
                                    ' <b><a href="' .
                                    folio_feeds_url( $arguments, $page, array( array( 'name'=>$option['var'],'value' => $option_value['name'] ) ) ) . 
                                    '">' . $option_value['caption'] . "</a></b> |"
                                : ' <b>' . $option_value['caption'] . '</b> |' );
                    } else { // !Selected
                        $html .= ' <a href="' .
                                folio_feeds_url( $arguments, $page,
                                    // If multiple options, then keep existing option available.
                                    //      Else, remove it. 
                                    ( $option['displaymode'] == 'multiple' ?
                                    array( array('name'=>$option['var'],'value' => $option_value['name'] ) ) :
                                    array( array('name'=>$option['var'], 'value' => $option_value['name'] ), 
                                        array('name'=>$option['var'],'value' => $arguments[$option['var']][0]) ) 
                                     ) ) .
                                '">' . $option_value['caption'] . "</a> |";
                    }
                }
            }
            $html = trim( $html, '|') .
                "\n</td></tr>";
        }

    }
    return $html . "</table><br/>\n";
}

/**
* Generic function used to remove an element from an array based off of the element's value (not key)
**/
function folio_delete_element( $array, $value ) {
    $i = 0;

    if ( !is_array( $array ) ) { return array(); }

    // Remove the element from the array.
    while ( !(($i = array_search( $value, $array )) === false) ) {
        //THough not noted in documentation, array_splice has side effect of removing element from
        //      array as well as returning the removed section as a return value.
        array_splice( $array, $i, 1);
    }

    return $array;
}

/**
* Create a new url from the given params
* Replace the variable referenced by Change to set to Value.  Makes it easier for array
*   processing.
* Note that if we are being told to remove the only value in the array that we will automatically
*   select the wildcard.
*
* @param $changes array - An array of arrays= ('name', 'value') to arg array.
**/
function folio_feeds_url( $arguments, $page, $changes  ) {
    global $CFG;

    foreach ( $changes as $change ) {
        // If this is an array, then flip it (add if !present, & reverse).
        if ( is_array($arguments[$change['name']]) ) {
            if ( in_array( $change['value'], $arguments[$change['name']])  ) { 
                // Remove
                $arguments[$change['name']] = folio_delete_element( $arguments[$change['name']], $change['value'] );
                // Test to make sure that there is at least one option.
                if ( count($arguments[$change['name']]) == 0 ) {
                    array_push( $arguments[$change['name']], 'all' );
                }
            } else {
                array_push($arguments[$change['name']], $change['value']);
            }
        } else {
            trigger_error('folio_feds_url was asked to change the value of a non-array ' . $change, E_USER_ERROR );
        }
    }

    // Create URL
    return $CFG->wwwroot . 'activity/' .
        implode( '+', $arguments['mode']) . '/' .
        implode( '+', $arguments['username']) . '/' .
        implode( '+', $arguments['format']) . '/' .
        implode( '+', $arguments['types']) . '/' .
        implode( '+', $arguments['tags']) . '/0'; // . $page;
}

?>